<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>percentiles 聚合 | ElasticSearch 7.7 权威指南中文版</title>
	<meta name="keywords" content="ElasticSearch 权威指南中文版, elasticsearch 7, es7, 实时数据分析，实时数据检索" />
    <meta name="description" content="ElasticSearch 权威指南中文版, elasticsearch 7, es7, 实时数据分析，实时数据检索" />
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
	<script>
	var _link = 'search-aggregations-metrics-percentile-aggregation.html';
    </script>
</head>
<body>
<div class="main-container">
    <section id="content">
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/reference/7.7/search-aggregations-metrics-percentile-aggregation.html" rel="nofollow" target="_blank">https://www.elastic.co/guide/en/elasticsearch/reference/7.7/search-aggregations-metrics-percentile-aggregation.html</a>, 原文档版权归 www.elastic.co 所有<br/>本地英文版地址: <a href="../en/search-aggregations-metrics-percentile-aggregation.html" rel="nofollow" target="_blank">../en/search-aggregations-metrics-percentile-aggregation.html</a></div>
                        <!-- start body -->
                  <div class="page_header">
<strong>重要</strong>: 此版本不会发布额外的bug修复或文档更新。最新信息请参考 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html" rel="nofollow">当前版本文档</a>。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch 权威指南 [7.7]</a></span>
»
<span class="breadcrumb-link"><a href="search-aggregations.html">聚合</a></span>
»
<span class="breadcrumb-link"><a href="search-aggregations-metrics.html">度量聚合</a></span>
»
<span class="breadcrumb-node">percentiles 聚合</span>
</div>
<div class="navheader">
<span class="prev">
<a href="search-aggregations-metrics-median-absolute-deviation-aggregation.html">« median_absolute_deviation 聚合</a>
</span>
<span class="next">
<a href="search-aggregations-metrics-percentile-rank-aggregation.html">percentile_ranks 聚合 »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="search-aggregations-metrics-percentile-aggregation"></a>百分位数(percentiles)聚合
</h2>
</div></div></div>
<p>
一个 <code class="literal">multi-value</code>(多值) 度量聚合，计算从聚合文档中提取的数值的一个或多个百分位数。

这些值可以由给定的脚本生成，也可以从文档中的特定数值或 <a class="xref" href="histogram.html" title="histogram 数据类型" rel="nofollow">histogram 字段</a> 中提取。
</p>
<p>
百分位数表示观察值出现一定百分比的点。  

例如，第 95 百分位是大于观察值的 95% 的值。
</p>
<p>
百分位数通常用于发现异常值。

在正态分布中，第 0.13 和 99.87 百分位代表平均值的 3 个标准差。

任何超出 3 个标准偏差的数据通常被认为是异常的。
</p>
<p>
当检索到一个百分比范围时，可以使用它们来估计数据分布，并确定数据是否倾斜、双峰等。
</p>
<p>
假设数据由网站加载时间组成。

加载时间的平均值和中值对管理员来说不是很有用。  

最大值可能很有趣，但它很容易被一个缓慢的响应所扭曲。
</p>
<p>
让我们看看代表加载时间(load_time)的百分比范围：
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time" <a id="CO194-1"></a><i class="conum" data-value="1"></i>
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/368.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO194-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>字段 <code class="literal">load_time</code> 必须是一个 numeric 类型的字段。</p>
</td>
</tr>
</table>
</div>
<p>
默认情况下，<code class="literal">percentile</code> 度量将生成一个百分位数范围：<code class="literal">[ 1, 5, 25, 50, 75, 95, 99 ]</code>。

响应将如下所示：
</p>
<div class="pre_wrapper lang-console-result">
<pre class="programlisting prettyprint lang-console-result">{
    ...

   "aggregations": {
      "load_time_outlier": {
         "values" : {
            "1.0": 5.0,
            "5.0": 25.0,
            "25.0": 165.0,
            "50.0": 445.0,
            "75.0": 725.0,
            "95.0": 945.0,
            "99.0": 985.0
         }
      }
   }
}</pre>
</div>
<p>
如你所见，该聚合返回默认范围内每个百分位的计算值。

如果假设响应时间以毫秒为单位，很明显网页通常在 10-725 毫秒内加载，但偶尔会达到 945-985毫秒。
</p>
<p>
通常，管理员只对异常值－极端的百分位数－感兴趣。

我们可以只指定我们感兴趣的百分比(请求的百分位数必须是0-100之间的值，包括0和100):
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time",
                "percents" : [95, 99, 99.9] <a id="CO195-1"></a><i class="conum" data-value="1"></i>
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/369.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO195-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>
使用 <code class="literal">percents</code> 参数指定要计算的特定百分位数
</p>
</td>
</tr>
</table>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_keyed_response"></a>keyed 响应
</h3>
</div></div></div>
<p>
默认情况下，<code class="literal">keyed</code> 标志设置为 <code class="literal">true</code>，它将唯一的字符串键与每个桶相关联，并将范围作为哈希而不是数组返回。

将 <code class="literal">keyed</code> 标志设置为 <code class="literal">false</code> 将禁用此行为：
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET latency/_search
{
    "size": 0,
    "aggs": {
        "load_time_outlier": {
            "percentiles": {
                "field": "load_time",
                "keyed": false
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/370.console"></div>
<p>响应：</p>
<div class="pre_wrapper lang-console-result">
<pre class="programlisting prettyprint lang-console-result">{
    ...

    "aggregations": {
        "load_time_outlier": {
            "values": [
                {
                    "key": 1.0,
                    "value": 5.0
                },
                {
                    "key": 5.0,
                    "value": 25.0
                },
                {
                    "key": 25.0,
                    "value": 165.0
                },
                {
                    "key": 50.0,
                    "value": 445.0
                },
                {
                    "key": 75.0,
                    "value": 725.0
                },
                {
                    "key": 95.0,
                    "value": 945.0
                },
                {
                    "key": 99.0,
                    "value": 985.0
                }
            ]
        }
    }
}</pre>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_script_10"></a>脚本
</h3>
</div></div></div>
<p>
百分位数度量支持脚本。

例如，如果加载时间是以毫秒为单位的，但我们希望以秒为单位计算百分位数，我们可以使用一个脚本来进行动态转换：
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "script" : {
                    "lang": "painless",
                    "source": "doc['load_time'].value / params.timeUnit", <a id="CO196-1"></a><i class="conum" data-value="1"></i>
                    "params" : {
                        "timeUnit" : 1000   <a id="CO196-2"></a><i class="conum" data-value="2"></i>
                    }
                }
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/371.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO196-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>
参数 <code class="literal">field</code> 被替换为 <code class="literal">script</code>，它使用脚本来生成计算百分位的值
</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO196-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>像任何其他脚本一样，这里的脚本支持参数化输入</p>
</td>
</tr>
</table>
</div>
<p>
<p>
这将使用 <a class="xref" href="modules-scripting-painless.html" title="Painless scripting language" rel="nofollow">painless</a>(无痛) 脚本语言，没有脚本参数。

要使用存储的脚本，请使用以下语法：
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "script" : {
                    "id": "my_script",
                    "params": {
                        "field": "load_time"
                    }
                }
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/372.console"></div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="search-aggregations-metrics-percentile-aggregation-approximation"></a>百分位数(通常)是近似值
</h3>
</div></div></div>
<p>
有许多不同的算法来计算百分位数。

简单的实现只是将所有的值存储在一个有序的数组中。

要找到第50个百分位数，只需找到位于 <code class="literal">my_array[count(my_array) * 0.5]</code> 的值。
</p>
<p>
显然，简单的实现是不可伸缩的——排序后的数组随着数据集中值的数量线性增长。

要计算 Elasticsearch 集群中潜在的数十亿个值的百分位数，需要计算<em>近似(approximate)</em>百分位数。
</p>
<p>
<code class="literal">percentile</code> 度量使用的算法称为 TDigest (由 Ted Dunning 在<a href="https://github.com/tdunning/t-digest/blob/master/docs/t-digest-paper/histo.pdf" class="ulink" target="_top">使用T-Digests计算精确分位数</a>中引入)。
</p>
<p>
使用这一度量时，需要记住一些准则：
</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
精度与 <code class="literal">q(1-q)</code> 成正比。

这意味着极端百分位数(例如99%)比不太极端的百分位数(例如中值)更准确
</li>
<li class="listitem">
对于小的数值集合，百分位数是高度准确的(如果数据足够小，可能是100%准确)。
</li>
<li class="listitem">
随着桶中值的数量增加，算法开始近似百分位数。

这实际上是在用准确性来减少内存的使用量。

不准确的确切程度很难概括，因为它取决于数据分布和要聚合的数据量
</li>
</ul>
</div>
<p>
下图显示了均匀分布的相对误差，它取决于采集值的数量和要求的百分位数:
</p>
<p><span class="image"><img src="../static/images/percentiles_error.png" alt="percentiles error"></span></p>
<p>
它显示了极端百分位数的精度更好。

对于大量的值，误差减小的原因是大数定律使值的分布越来越均匀，t-digest 树可以更好地进行汇总。 

在偏态分布上就不是这样了。  
</p>
<div class="warning admon">
<div class="icon"></div>
<div class="admon_content">
<p>
百分位数聚合也是<a href="https://en.wikipedia.org/wiki/Nondeterministic_algorithm" class="ulink" target="_top">不确定的(non-deterministic)</a>。

这意味着使用相同的数据可以得到稍微不同的结果。
</p>
</div>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="search-aggregations-metrics-percentile-aggregation-compression"></a>压缩(compression)
</h3>
</div></div></div>
<p>
近似算法必须平衡内存利用率和估计精度。

这种平衡可以使用参数 <code class="literal">compression</code> 来控制:
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time",
                "tdigest": {
                  "compression" : 200 <a id="CO197-1"></a><i class="conum" data-value="1"></i>
                }
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/373.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO197-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">compression</code> 控制内存使用和近似误差</p>
</td>
</tr>
</table>
</div>
<p>
TDigest算法使用多个“节点”来近似百分位数，可用的节点越多，与数据量成比例的精度(和大内存占用)就越高。

参数 <code class="literal">compression</code> 将最大节点数限制为 <code class="literal">20 * compression</code>。
</p>
<p>
因此，通过增加 <code class="literal">compression</code> 的值，可以以更多内存为代价来提高百分位数的准确性。

较大的 <code class="literal">compression</code> 值也会使算法变慢，因为底层树数据结构的大小会增加，从而导致更昂贵的操作。  

<code class="literal">compression</code> 的默认值为 <code class="literal">100</code>。
</p>
<p>
一个“节点”使用大约 32 字节的内存，因此在最坏的情况下(大量数据被排序并按顺序到达)，默认设置将产生大约 64KB 大小的 TDigest。

实际上，数据往往更加随机，TDigest 将使用更少的内存。
</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_hdr_histogram"></a>HDR 直方图(Histogram)
</h3>
</div></div></div>
<div class="note admon">
<div class="icon"></div>
<div class="admon_content">
<p>
此设置公开了 HDR 直方图的内部实现，语法将来可能会改变。
</p>
</div>
</div>
<p>
<a href="https://github.com/HdrHistogram/HdrHistogram" class="ulink" target="_top" rel="nofollow">HDR直方图</a> (High Dynamic Range Histogram, 高动态范围直方图)是一种替代实现，在计算延迟测量的百分位数时非常有用，因为它比 t-digest 实现更快，但需要更大的内存。

这种实现保持固定的最坏情况百分比误差(指定为有效数字的数量)。

这意味着，如果在设置为 3 个有效数字的直方图中记录的数据值从 1 微秒到 1 小时(3,600,000,000微秒)，则对于 1 毫秒和 3.6 秒(或更好)的最大跟踪值(1小时)，它将保持 1 微秒的值分辨率。
</p>
<p>
通过在请求中指定参数 <code class="literal">method</code>，可以使用 HDR 直方图:
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time",
                "percents" : [95, 99, 99.9],
                "hdr": { <a id="CO198-1"></a><i class="conum" data-value="1"></i>
                  "number_of_significant_value_digits" : 3 <a id="CO198-2"></a><i class="conum" data-value="2"></i>
                }
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/374.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO198-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>
<code class="literal">hdr</code> 对象表示应该使用HDR直方图来计算百分位数，并且可以在对象内部指定该算法的特定设置
</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO198-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>
<code class="literal">number_of_significant_value_digits</code> 指定直方图数值的分辨率，以有效位数表示
</p>
</td>
</tr>
</table>
</div>
<p>
HDR 直方图仅支持正值，如果向其传递负值，将会出错。

如果值的范围未知，使用HDR 直方图也不是一个好主意，因为这可能会导致很高的内存使用率。
</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_missing_value_9"></a>缺失的值
</h3>
</div></div></div>
<p>
参数 <code class="literal">missing</code> 定义应该如何处理有缺失值的文档。

默认情况下，它们会被忽略，但也可以将它们视为有一个(默认)值。
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">GET latency/_search
{
    "size": 0,
    "aggs" : {
        "grade_percentiles" : {
            "percentiles" : {
                "field" : "grade",
                "missing": 10 <a id="CO199-1"></a><i class="conum" data-value="1"></i>
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/375.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO199-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>
<code class="literal">grade</code> 字段中没有值的文档将与值为 <code class="literal">10</code> 的文档落入同一个桶。
</p>
</td>
</tr>
</table>
</div>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="search-aggregations-metrics-median-absolute-deviation-aggregation.html">« median_absolute_deviation 聚合</a>
</span>
<span class="next">
<a href="search-aggregations-metrics-percentile-rank-aggregation.html">percentile_ranks 聚合 »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>